Skip to content

Update __init__.py to handle short report lengths. #18

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

Tobbinloggin
Copy link

@Tobbinloggin Tobbinloggin commented Mar 21, 2025

I added a check to readone that prevents a crash if the returned report is shorter than expected.

I encountered an issue with my code crashing due to some of the reports being shorter than expected, this stop-gap addition prevents the code from crashing out.

Added a check to readone that prevents a crash if the returned report is shorter than expected
@luigifab
Copy link
Owner

luigifab commented Mar 21, 2025

can you try this version?

diff --git a/src/radexreader/__init__.py b/src/radexreader/__init__.py
index 4238f6c238..6a42905cb2 100644
--- a/src/radexreader/__init__.py
+++ b/src/radexreader/__init__.py
@@ -278,30 +278,32 @@
 
 		self.hid_set_report((0x7b, 0xff, 0x20, 0, 0x06, 0, self.keyA, self.keyB, 0, 0, self.keyC, self.keyD, 0, 0x08, 0x0c, 0, 0xf3, 0xf7))
 		hexa = self.hid_get_report()
+		if hexa != b'' and len(hexa) >= 31:
+			# measure   = 0.15 µSv/h = 15 / 0.15 µSv accumulated = 15 / 15 CPM = 15
+			measure     = (hexa[20] + hexa[21] * 256 + hexa[22] * 256 * 256) / 100
+			measure_acc = (hexa[24] + hexa[25] * 256 + hexa[26] * 256 * 256) / 100
+			measure_cpm =  hexa[28] + hexa[29] * 256 + hexa[30] * 256 * 256
+			# uncertainty of the result
+			percent     = 15 + 6 / measure
+			measure_min = measure * (1 - percent / 100)
+			measure_max = measure * (1 + percent / 100)
+			if measure_min < 0:
+				measure_min = 0
+			if percent > 99.9:
+				percent = 99.9
+			# most recent measure
+			timestamp = int(time.time())
+			return { timestamp: {
+				'pct':  percent,
+				'min':  measure_min,
+				'val':  measure,
+				'max':  measure_max,
+				'acc':  measure_acc,
+				'cpm':  measure_cpm,
+				'time': timestamp
+			} }
 
-		# measure   = 0.15 µSv/h = 15 / 0.15 µSv accumulated = 15 / 15 CPM = 15
-		measure     = (hexa[20] + hexa[21] * 256 + hexa[22] * 256 * 256) / 100
-		measure_acc = (hexa[24] + hexa[25] * 256 + hexa[26] * 256 * 256) / 100
-		measure_cpm =  hexa[28] + hexa[29] * 256 + hexa[30] * 256 * 256
-		# uncertainty of the result
-		percent     = 15 + 6 / measure
-		measure_min = measure * (1 - percent / 100)
-		measure_max = measure * (1 + percent / 100)
-		if measure_min < 0:
-			measure_min = 0
-		if percent > 99.9:
-			percent = 99.9
-
-		timestamp = int(time.time())
-		return { timestamp: {
-			'pct': percent,
-			'min': measure_min,
-			'val': measure,
-			'max': measure_max,
-			'acc': measure_acc,
-			'cpm': measure_cpm,
-			'time': timestamp
-		} }
+		return {}
 
 	def erase(self):
 		if self.com == 'RD1212v2':

it's similar between RD1212 and One, and without print

@Tobbinloggin
Copy link
Author

Tobbinloggin commented Mar 23, 2025

It appears that applying that patch caused everything that's returned to be empty. When I reverted to the old code it started returning data again.

I was testing why that was, but I didn't figure it out.

@luigifab
Copy link
Owner

loool, I suppose this line: if hexa != b'' and len(hexa) >= 31:
your line is: if not hexa or len(hexa) < 31:
so maybe: if hexa and len(hexa) >= 31:

@Tobbinloggin
Copy link
Author

Tobbinloggin commented Mar 23, 2025

Okay, I'll try that instead. Interesting piece of information, I set up InfluxDB and Grafana with RadexReader and looking at the data from a zoomed out view it appears these periods of missing data are cyclic.
image

@luigifab
Copy link
Owner

luigifab commented Mar 23, 2025

Oh so nice!

There is probably something wrong with the addresses used to read data from the Radex ONE.
There is a "for", the idea is:

  • current measure is stored at address 1
  • a moment later
  • current measure is stored at address 2
  • a moment later
  • current measure is stored at address 3
  • ...

But the address is not "simple": self.hid_set_report((0x7b, 0xff, 0x20, 0, 0x06, 0, self.keyA, self.keyB, 0, 0, self.keyC, self.keyD, 0, 0x08, 0x0c, 0, 0xf3, 0xf7))

@luigifab luigifab requested a review from Copilot June 16, 2025 20:12
Copy link

@Copilot Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds a safeguard in readOne to prevent crashes when the HID report is shorter than expected.

  • Introduces a length check for the received report and early return on incomplete data
  • Emits a warning and returns an empty dict when the report is too short
Comments suppressed due to low confidence (1)

src/radexreader/init.py:282

  • Add unit tests covering the new branch where hexa is None or shorter than expected to validate this behavior and prevent regressions.
# Check if the returned report has the expected length

@luigifab
Copy link
Owner

luigifab commented Jul 25, 2025

It look like that there are negative values with current code:

iteration	keyA	keyB	keyC	keyD
1	0x00	0x00	0x5e	0x00
2	0x04	0x00	0x5a	0x00
3	0x08	0x00	0x56	0x00
4	0x0c	0x00	0x52	0x00
5	0x10	0x00	0x4e	0x00
6	0x14	0x00	0x4a	0x00
7	0x18	0x00	0x46	0x00
8	0x1c	0x00	0x42	0x00
9	0x20	0x00	0x3e	0x00
10	0x24	0x00	0x3a	0x00
11	0x28	0x00	0x36	0x00
12	0x2c	0x00	0x32	0x00
13	0x30	0x00	0x2e	0x00
14	0x34	0x00	0x2a	0x00
15	0x38	0x00	0x26	0x00
16	0x3c	0x00	0x22	0x00
17	0x40	0x00	0x1e	0x00
18	0x44	0x00	0x1a	0x00
19	0x48	0x00	0x16	0x00
20	0x4c	0x00	0x12	0x00
21	0x50	0x00	0x0e	0x00
22	0x54	0x00	0x0a	0x00
23	0x58	0x00	0x06	0x00
24	0x5c	0x00	0x02	0x00
25	0x60	0x00	0x-2	0x00
26	0x64	0x00	0x-6	0x00
27	0x68	0x00	0x-a	0x00
28	0x6c	0x00	0x-e	0x00
29	0x70	0x00	0x-12	0x00
30	0x74	0x00	0x-16	0x00
31	0x78	0x00	0x-1a	0x00
32	0x7c	0x00	0x-1e	0x00
33	0x80	0x00	0x-22	0x00
34	0x84	0x00	0x-26	0x00
35	0x88	0x00	0x-2a	0x00
36	0x8c	0x00	0x-2e	0x00
37	0x90	0x00	0x-32	0x00
38	0x94	0x00	0x-36	0x00
39	0x98	0x00	0x-3a	0x00
40	0x9c	0x00	0x-3e	0x00
41	0xa0	0x00	0x-42	0x00
42	0xa4	0x00	0x-46	0x00
43	0xa8	0x00	0x-4a	0x00
44	0xac	0x00	0x-4e	0x00
45	0xb0	0x00	0x-52	0x00
46	0xb4	0x00	0x-56	0x00
47	0xb8	0x00	0x-5a	0x00
48	0xbc	0x00	0x-5e	0x00
49	0xc0	0x00	0x-62	0x00
50	0xc4	0x00	0x-66	0x00
51	0xc8	0x00	0x-6a	0x00
52	0xcc	0x00	0x-6e	0x00
53	0xd0	0x00	0x-72	0x00
54	0xd4	0x00	0x-76	0x00
55	0xd8	0x00	0x-7a	0x00
56	0xdc	0x00	0x-7e	0x00
57	0xe0	0x00	0x-82	0x00
58	0xe4	0x00	0x-86	0x00
59	0xe8	0x00	0x-8a	0x00
60	0xec	0x00	0x-8e	0x00
61	0xf0	0x00	0x-92	0x00
62	0xf4	0x00	0x-96	0x00
63	0xf8	0x00	0x-9a	0x00
64	0xfc	0x00	0x-9e	0x00
65	0x02	0x01	0x5d	0xff
66	0x06	0x01	0x59	0xff
67	0x0a	0x01	0x55	0xff
68	0x0e	0x01	0x51	0xff
69	0x12	0x01	0x4d	0xff
70	0x16	0x01	0x49	0xff
71	0x1a	0x01	0x45	0xff
72	0x1e	0x01	0x41	0xff
73	0x22	0x01	0x3d	0xff
74	0x26	0x01	0x39	0xff
75	0x2a	0x01	0x35	0xff
76	0x2e	0x01	0x31	0xff
77	0x32	0x01	0x2d	0xff
78	0x36	0x01	0x29	0xff
79	0x3a	0x01	0x25	0xff
80	0x3e	0x01	0x21	0xff
81	0x42	0x01	0x1d	0xff
82	0x46	0x01	0x19	0xff
83	0x4a	0x01	0x15	0xff
84	0x4e	0x01	0x11	0xff
85	0x52	0x01	0x0d	0xff
86	0x56	0x01	0x09	0xff
87	0x5a	0x01	0x05	0xff
88	0x5e	0x01	0x01	0xff
89	0x62	0x01	0x-3	0xff
90	0x66	0x01	0x-7	0xff
91	0x6a	0x01	0x-b	0xff
92	0x6e	0x01	0x-f	0xff
93	0x72	0x01	0x-13	0xff
94	0x76	0x01	0x-17	0xff
95	0x7a	0x01	0x-1b	0xff
96	0x7e	0x01	0x-1f	0xff
97	0x82	0x01	0x-23	0xff
98	0x86	0x01	0x-27	0xff
99	0x8a	0x01	0x-2b	0xff
100	0x8e	0x01	0x-2f	0xff
101	0x92	0x01	0x-33	0xff
102	0x96	0x01	0x-37	0xff
103	0x9a	0x01	0x-3b	0xff
104	0x9e	0x01	0x-3f	0xff
105	0xa2	0x01	0x-43	0xff
106	0xa6	0x01	0x-47	0xff
107	0xaa	0x01	0x-4b	0xff
108	0xae	0x01	0x-4f	0xff
109	0xb2	0x01	0x-53	0xff
110	0xb6	0x01	0x-57	0xff
111	0xba	0x01	0x-5b	0xff
112	0xbe	0x01	0x-5f	0xff
113	0xc2	0x01	0x-63	0xff
114	0xc6	0x01	0x-67	0xff
115	0xca	0x01	0x-6b	0xff
116	0xce	0x01	0x-6f	0xff
117	0xd2	0x01	0x-73	0xff
118	0xd6	0x01	0x-77	0xff
119	0xda	0x01	0x-7b	0xff
120	0xde	0x01	0x-7f	0xff
121	0xe2	0x01	0x-83	0xff
122	0xe6	0x01	0x-87	0xff
123	0xea	0x01	0x-8b	0xff
124	0xee	0x01	0x-8f	0xff
125	0xf2	0x01	0x-93	0xff
126	0xf6	0x01	0x-97	0xff
127	0xfa	0x01	0x-9b	0xff
128	0xfe	0x01	0x-9f	0xff
129	0x04	0x02	0x5c	0xfe
130	0x08	0x02	0x58	0xfe
131	0x0c	0x02	0x54	0xfe
132	0x10	0x02	0x50	0xfe
133	0x14	0x02	0x4c	0xfe
134	0x18	0x02	0x48	0xfe
135	0x1c	0x02	0x44	0xfe
136	0x20	0x02	0x40	0xfe
...

with ChatGPT I tried some stupid things, and there is still something wrong, because his helper made never breaks:

import csv

# the correct initial values
keyA = 0x04 - 0x04  # => 0x00
keyB = 0x00
keyC = 0x5a + 0x04  # => 0x5e
keyD = 0x00

seen = set()
rows = []
iteration = 1

while iteration <= 10000:
    t = (keyA, keyB, keyC, keyD)
    if t in seen:
        break
    seen.add(t)
    rows.append([iteration, f"0x{keyA:02x}", f"0x{keyB:02x}", f"0x{keyC:02x}", f"0x{keyD:02x}"])
    iteration += 1

    keyA += 0x04
    keyC -= 0x04

    if keyA > 0xff:
        keyA -= 0xfe
        keyB += 0x01
        if keyB > 0xff:
            keyB = 0x00
        keyC -= 0x01
    elif keyC < 0x00:
        keyC += 0xff
        keyD -= 0x01
        if keyD < 0x00:
            keyD = 0xff

with open("radex_keys_cycle.csv", "w", newline="") as csvfile:
    writer = csv.writer(csvfile, delimiter="\t")
    writer.writerow(["iteration", "keyA", "keyB", "keyC", "keyD"])
    writer.writerows(rows)

@luigifab
Copy link
Owner

luigifab commented Jul 25, 2025

It could be nice to know which address crash in your beautiful graph. I suppose that the beginning of the iteration is correct, we need to identify working addresses, and the first one that crash (len(hexa) < 31:).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants